#include "nosal/exec/execution_client.h"
#include "nosal/exec/exec_error_domain.h"
//#include "nosal/exec/internal/pipe_write_end.h"
//#include "nosal/exec/internal/pipe_read_end.h"
//#include "nosal/exec/internal/constant.h"
//#include "nosal/exec/internal/serialization.h"
#include "nosal/log/logger.h"
#include "nosal/log/logging.h"

#include <unistd.h>
#include <chrono>
#include <thread>

namespace netaos {
namespace nosal {
namespace exec {

namespace
{
netaos::nosal::log::Logger& GetLogger()
{
    static netaos::nosal::log::Logger& logger
        = netaos::nosal::log::CreateLogger("EXCL", "Execution Client implementation", netaos::nosal::log::LogLevel::kInfo);
    return logger;
}

netaos::nosal::core::Result<void> sendExecutionStateReportRequest(ExecutionState state)
{
        ///
        /// TODO: message passing
        ///
    return netaos::nosal::core::Result<void>::FromValue();
}
netaos::nosal::core::Result<void> waitExecutionStateReportResponse(ExecutionStateResponseStatus& status)
{
        ///
        /// TODO: message passing
        ///
    status = ExecutionStateResponseStatus::kSuccess;
    return netaos::nosal::core::Result<void>::FromValue();
}

}  // namespace

ExecutionClient::ExecutionClient() noexcept
{ }

ExecutionClient::~ExecutionClient() noexcept
{ }

netaos::nosal::core::Result<void> ExecutionClient::ReportExecutionState(ExecutionState state) const noexcept
{
    try {
        ExecutionStateResponseStatus response_status;
        sendExecutionStateReportRequest(state);
       // constexpr static std::chrono::milliseconds sleep_time(25);
       // std::this_thread::sleep_for(sleep_time);
        waitExecutionStateReportResponse(response_status);

        if (response_status == ExecutionStateResponseStatus::kSuccess) {
            GetLogger().LogInfo() << "Received confirmation of Execution State Running report.";
            return netaos::nosal::core::Result<void>::FromValue();
        } else if (response_status == ExecutionStateResponseStatus::kInvalidTransition
            || response_status == ExecutionStateResponseStatus::kInvalidReport) {
            GetLogger().LogError() << "Execution state report was rejected as the report was invalid or wrong.";
            return netaos::nosal::core::Result<void>::FromError(netaos::nosal::exec::MakeErrorCode(
                netaos::nosal::exec::ExecErrc::kInvalidTransition, netaos::nosal::core::ErrorDomain::SupportDataType{0}));
        } else if (response_status == ExecutionStateResponseStatus::kReportNotAllowed) {
            netaos::nosal::core::Abort("ExecutionClient::ReportExecutionState invoked by non-reporting Process.");
        }

        GetLogger().LogInfo() << "Encountered timeout for response after Execution State report.";
        return netaos::nosal::core::Result<void>::FromValue();
    } catch (const std::exception& ex) {
        GetLogger().LogError() << "Caught exception during ReportExecutionState() with message:" << ex.what();
        return netaos::nosal::core::Result<void>::FromError(netaos::nosal::exec::MakeErrorCode(
            netaos::nosal::exec::ExecErrc::kCommunicationError, netaos::nosal::core::ErrorDomain::SupportDataType{0}));
    } catch (...) {
        GetLogger().LogError() << "Unknown error occured during ReportExecutionState().";
        return netaos::nosal::core::Result<void>::FromError(
            netaos::nosal::exec::MakeErrorCode(netaos::nosal::exec::ExecErrc::kGeneralError, netaos::nosal::core::ErrorDomain::SupportDataType{0}));
    }
}

}  // namespace exec
}  // namespace nosal
}  // namespace netaos
